﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SqlMiM.Common.Interfaces;
using System.Collections;
using SqlMiM.Common.Sql;
using System.Data.SqlServerCe;
using System.Reflection;
using System.ComponentModel;
using System.Globalization;

namespace SqlMiM.Common.Framework.Configuration
{
    public class ConfigurationService : IConfigurationService, INotifyPropertyChanged
    {
        #region Singleton

        private static ConfigurationService current;

        public static ConfigurationService Current
        {
            get
            {
                if (current == null)
                {
                    current = new ConfigurationService();
                }

                return current;
            }
        }

        #endregion

        /// <summary>
        /// Sql Ce Pooled Connection
        /// </summary>
        private SqlCePoolConnection connexion;

        /// <summary>
        /// All Configurations : Expected : one per Plugin
        /// </summary>
        public SortedList<String, ConfigurationObject> Configurations { get; private set; }

        /// <summary>
        /// Get a Configuration Object for one Plugin identified by its name.
        /// </summary>
        public ConfigurationObject this[string pluginName]
        {
            get
            {
                if (this.Configurations.ContainsKey(pluginName))
                    return this.Configurations[pluginName];

                ConfigurationObject co = new ConfigurationObject(pluginName);
               
                this.Configurations.Add(pluginName, co);

                return co;
            }
            set
            {
                if (value == null)
                {
                    if (this.Configurations.ContainsKey(pluginName))
                        this.Configurations.Remove(pluginName);
                }
                else
                {
                    if (this.Configurations.ContainsKey(pluginName))
                        this.Configurations[pluginName] = value;
                    else
                        this.Configurations.Add(pluginName, value);

                }
            }

        }
        
        /// <summary>
        /// Connection to my sdf
        /// </summary>
        public string ConfigurationConnectionString
        {
            get { return Context.Current.ConfigurationSqlCeConnectionString; }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public ConfigurationService()
        {
            // Create the configurations objects
            this.Configurations = new SortedList<String, ConfigurationObject>();

        }

        /// <summary>
        /// Load all properties
        /// </summary>
        public void Load()
        {
            this.Configurations.Clear();

            try
            {
                // Get a pooled Connexion
                this.connexion = SqlCePoolConnection.CreateSqlCePooledConnection(ConfigurationConnectionString, true);

                SqlCeCommand command = SqlCeCommands.CreateCommand(connexion, SqlCeCommands.SELECT_ALL_CONFIGS);

                this.connexion.Open();

                SqlCeDataReader reader = command.ExecuteReader();

                while (reader.Read())
                {
                    String pluginName = reader["Plugin"] as String;
                    String name = reader["Name"] as String;
                    String tmp = reader["Type"] as String ;
                    String value = reader["Value"] as String;

                    // Get Configuration Object (Will be Created if not exists)
                    ConfigurationObject co = this[pluginName];

                    // Load in configurationObject the value, typed.
                    co.Load(name, tmp, value);
  
                }
            }
            catch (Exception)
            {

            }
            finally
            {
                connexion.Close();
            }
        }

        /// <summary>
        /// Save all ObjectConfigurations
        /// </summary>
        public void Save()
        {
            if (this.Configurations == null || this.Configurations.Values == null)
                return;

            foreach (ConfigurationObject co in this.Configurations.Values)
            {
                string[] array = new string[co.Properties.Count];
                co.Properties.Keys.CopyTo(array, 0);

                if (array.Length == 0) continue;

                foreach (string propertyName in array)
                {
                    // Get Value
                    Object value = co.GetProperty(propertyName);

                    // Get Type
                    Type type = value.GetType();

                    // Get typeName
                    String typeName =  type.FullName;

                    // Get value in text format
                    String valueText = TypeDescriptor.GetConverter(type).ConvertToString(null, CultureInfo.InvariantCulture, value);

                    try
                    {
                        // Get a pooled Connexion
                        this.connexion = SqlCePoolConnection.CreateSqlCePooledConnection(ConfigurationConnectionString, true);

                        // Get SqlCeCommand to Check if param already Exist
                        SqlCeCommand cmdCheck = SqlCeCommands.CreateCommand(connexion, SqlCeCommands.SELECT_CONFIG, true, co.PluginName, propertyName);
                        SqlCeCommand cmd = null;

                        this.connexion.Open();

                        SqlCeDataReader dr = cmdCheck.ExecuteReader();

                        // dr.HasRows not supported, so hack like this ...
                        while (dr.Read())
                            cmd = SqlCeCommands.CreateCommand(connexion, SqlCeCommands.UPDATE_CONFIG, true, co.PluginName, propertyName, typeName, valueText);
                        
                        // if cmd is null, no rows so Insert
                        if (cmd == null)
                            cmd = SqlCeCommands.CreateCommand(connexion, SqlCeCommands.INSERT_CONFIG, true, co.PluginName, propertyName, typeName, valueText);

                        cmd.ExecuteNonQuery();

                        this.connexion.Close();


                        

                        
                    }
                    catch (Exception)
                    {
                    }
                    finally
                    {
                        this.connexion.Close();
                    }
                }
              
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(PropertyChangedEventArgs e)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, e);
            }
        }


    }
}
